{{!

  Copyright 2016 Facebook, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

}}{{!

Wraps structs and exceptions defined in the thrift interface file and implemented
in the cpp2 generated code. This file just exposes the C++ classes and attributes
to Cython. The Pythonic wrappers of the individual structs and fields are
implemented in the Struct.pyx file.

}}
{{> common/AutoGeneratedPy}}

from libcpp.string cimport string
from libcpp cimport bool as cbool
from cpython cimport bool as pbool
from libc.stdint cimport int8_t, int16_t, int32_t, int64_t
from libcpp.memory cimport shared_ptr, unique_ptr
from libcpp.vector cimport vector
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap, pair as cpair
from thrift.py3.exceptions cimport cTException
cimport folly.iobuf as __iobuf
cimport thrift.py3.exceptions
cimport thrift.py3.types
from folly.optional cimport cOptional
{{#program:includeNamespaces}}
cimport {{#includeNamespace}}{{value}}.{{/includeNamespace}}types as _{{#includeNamespace}}{{value}}_{{/includeNamespace}}types
{{/program:includeNamespaces}}
{{#program:extraNamespaces}}
cimport {{#extraNamespace}}{{value}}.{{/extraNamespace}}types as _{{#extraNamespace}}{{value}}_{{/extraNamespace}}types
{{/program:extraNamespaces}}

{{#program:cppIncludes}}
cdef extern from "{{path}}":
  pass
{{/program:cppIncludes}}{{!
}}{{#program:customTemplates}}
{{> CustomTemplate}}
{{/program:customTemplates}}{{!
}}{{#program:customTypes}}
{{> CustomType}}
{{/program:customTypes}}

{{#program:enums}}
{{#first?}}
cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_types.h"{{!
}} namespace "{{#program:cppNamespaces}}{{value}}{{^last?}}::{{/last?}}{{/program:cppNamespaces}}":
{{/first?}}
    cdef cppclass c{{enum:name}} "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{enum:name}}":
        bint operator==(c{{enum:name}}&)
    {{#enum:values}}
    c{{enum:name}} {{enum:name}}__{{enumValue:name}} "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{enum:name}}::{{enumValue:origName}}"
    {{/enum:values}}
{{/program:enums}}


{{> types/enumDefs }}

{{#program:structs}}
{{#first?}}
cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_types_custom_protocol.h"{{!
}} namespace "{{#program:cppNamespaces}}{{value}}{{^last?}}::{{/last?}}{{/program:cppNamespaces}}":
{{/first?}}
    # Forward Declaration
    cdef cppclass c{{struct:name}} "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}"{{#struct:exception?}}(cTException){{/struct:exception?}}
{{/program:structs}}

{{#program:structs}}
{{#first?}}
cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_types.h"{{!
}} namespace "{{#program:cppNamespaces}}{{value}}{{^last?}}::{{/last?}}{{/program:cppNamespaces}}":
{{/first?}}
    {{^struct:union?}}
    cdef cppclass c{{struct:name}}__isset "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::__isset":
    {{#struct:fields}}
        bint {{field:name}}{{#field:hasModifiedName?}} "{{field:origName}}"{{/field:hasModifiedName?}}
    {{/struct:fields}}
    {{^struct:fields}}
        pass
    {{/struct:fields}}
    {{/struct:union?}}
    {{#struct:union?}}
    cdef enum c{{struct:name}}__type "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::Type":
        c{{struct:name}}__type___EMPTY__ "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::Type::__EMPTY__",
    {{#struct:fields}}
        c{{struct:name}}__type_{{field:name}} "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::Type::{{field:origName}}",
    {{/struct:fields}}
    {{/struct:union?}}

    cdef cppclass c{{struct:name}} "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}"{{#struct:exception?}}(cTException){{/struct:exception?}}:
        c{{struct:name}}() except +
        c{{struct:name}}(const c{{struct:name}}&) except +
        bint operator==(c{{struct:name}}&)
    {{^struct:union?}}
    {{#struct:fields}}
        {{#field:type}}{{> types/CythonCppStructFieldType}}{{/field:type}} {{field:name}}{{#field:hasModifiedName?}} "{{field:origName}}"{{/field:hasModifiedName?}}
    {{/struct:fields}}
        c{{struct:name}}__isset __isset
    {{/struct:union?}}
    {{#struct:union?}}
        c{{struct:name}}__type getType() const
    {{#struct:fields}}
        {{#field:type}}const {{> types/CythonCppStructFieldType}}& get_{{field:name}}{{#field:hasModifiedName?}} "get_{{field:origName}}"{{/field:hasModifiedName?}}() const{{/field:type}}
        {{! Note that the set methods don't take in a shared/unique_ptr, they just take in an object ref,
            but they return the appropriate ptr }}
        {{#field:type}}{{> types/CythonCppStructFieldType}}& set_{{field:name}}{{#field:hasModifiedName?}} "set_{{field:origName}}"{{/field:hasModifiedName?}}(const {{> types/CythonCppType}}&){{/field:type}}
    {{/struct:fields}}{{/struct:union?}}

{{/program:structs}}{{!

}}{{#program:structs}}{{#struct:fields}}{{#field:reference?}}
    {{! Hacky workaround to get shared_ptr's aliasing constructor since it
        doesn't seem doable with Cython's template support. Note that this may
        create multiple copies of the same definition, so we have to have unambiguous
        names (it seems like it should be fine since they're all extern, but in
        practice I'm getting "ambiguous overloaded method" errors with container
        types)}}
    cdef shared_ptr[{{#field:type}}{{> types/CythonCppType}}{{/field:type}}] {{!
    }}aliasing_constructor_{{field:name}} {{!
    }}"std::shared_ptr<{{!
    }}{{#field:type}}{{> types/CppValueType}}{{/field:type}}{{!
    }}>"(shared_ptr[c{{struct:name}}]&, {{!
    }}{{#field:type}}{{> types/CythonCppType}}{{/field:type}}*)
{{/field:reference?}}{{/struct:fields}}{{/program:structs}}

{{#program:structs}}
{{#first?}}cdef extern from "<utility>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[c{{struct:name}}] move(unique_ptr[c{{struct:name}}])
    cdef shared_ptr[c{{struct:name}}] move_shared "std::move"(shared_ptr[c{{struct:name}}])
    cdef unique_ptr[c{{struct:name}}] move_unique "std::move"(unique_ptr[c{{struct:name}}]){{/program:structs}}

{{#program:structs}}
{{#first?}}cdef extern from "<memory>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[const c{{struct:name}}] const_pointer_cast {{!
    }}"std::const_pointer_cast<const {{!
    }}{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}{{!
    }}>"(shared_ptr[c{{struct:name}}]){{/program:structs}}

{{#program:structs}}
{{#struct:union?}}
cdef class __{{struct:name}}Type(thrift.py3.types.CompiledEnum):
    pass


{{/struct:union?}}
# Forward Definition of the cython struct
cdef class {{struct:name}}({{> types/PythonStructClass}})


cdef class {{struct:name}}({{> types/PythonStructClass}}):
    cdef object __hash
    cdef object __weakref__
    cdef shared_ptr[c{{struct:name}}] _cpp_obj
    {{^struct:union?}}
    {{!Memoized Python wrappers of struct fields, created lazily}}
    {{#struct:fields}}
    {{#field:type}}{{#type:struct}}
    cdef {{> types/CythonPythonType}} __{{field:name}}
    {{/type:struct}}{{#type:container?}}
    cdef {{> types/CythonPythonType}} __{{field:name}}
    {{/type:container?}}{{#field:iobuf?}}
    cdef __iobuf.IOBuf __{{field:name}}
    {{/field:iobuf?}}{{#field:iobuf_ref?}}
    cdef __iobuf.IOBuf __{{field:name}}
    {{/field:iobuf_ref?}}{{/field:type}}
    {{/struct:fields}}{{/struct:union?}}
    {{#struct:union?}}
    cdef readonly __{{struct:name}}Type type
    cdef readonly object value
    cdef _load_cache({{struct:name}} self)
    {{/struct:union?}}

    @staticmethod
    cdef unique_ptr[c{{struct:name}}] _make_instance(
        c{{struct:name}}* base_instance{{#struct:fields}},
        object {{field:name}}{{/struct:fields}}
    ) except *

    @staticmethod
    cdef create(shared_ptr[c{{struct:name}}])

{{/program:structs}}

{{#program:containerTypes}}
cdef class {{type:flat_name}}:
    cdef object __hash
    cdef object __weakref__
    cdef shared_ptr[{{> types/CythonCppType}}] _cpp_obj
    @staticmethod
    cdef create(shared_ptr[{{> types/CythonCppType}}])
    @staticmethod
    cdef unique_ptr[{{> types/CythonCppType}}] _make_instance(object items) except *

{{/program:containerTypes}}{{#program:moveContainerTypes}}
{{#first?}}cdef extern from "<utility>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[{{> types/CythonCppType}}] move(unique_ptr[{{> types/CythonCppType}}])
    cdef unique_ptr[{{> types/CythonCppType}}] move_unique "std::move"(unique_ptr[{{> types/CythonCppType}}]){{!
}}{{/program:moveContainerTypes}}{{!

}}{{#program:moveContainerTypes}}
{{#first?}}
cdef extern from "<memory>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[const {{> types/CythonCppType}}] const_pointer_cast {{!
    }}"std::const_pointer_cast<const {{> types/CppValueType}}>"{{!
    }}(shared_ptr[{{> types/CythonCppType}}]){{/program:moveContainerTypes}}

{{#program:constants}}
{{#first?}}cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_constants.h"{{!
}} namespace "{{#program:cppNamespaces}}{{value}}{{^last?}}::{{/last?}}{{/program:cppNamespaces}}":{{/first?}}
    {{#constant:type}}
    cdef {{^type:string?}}{{> types/CythonCppType}}{{/type:string?}}{{#type:string?}}const char*{{/type:string?}} {{!
    }}c{{constant:name}} "{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{program:name}}_constants::{{constant:name}}"{{!
    }}{{#type:struct?}}(){{/type:struct?}}{{#type:string?}}(){{/type:string?}}{{#type:binary?}}(){{/type:binary?}}{{#type:container?}}(){{/type:container?}}{{#type:enum?}}(){{/type:enum?}}{{/constant:type}}{{/program:constants}}
